/*************************************************************************
|                                                                        |
|   IFPROC.C                                                    08.12.93 |
|   ADMAKE Utility:  process conditionals                                |
|                                                                        |
*************************************************************************/

#define MAXIF 10

#ifdef VMS
#include STDIO
#include STRING
#include STDLIB
#include CTYPE
#include "h.h"
#else
#include <stdio.h>
#include <string.h>
#ifdef HEAP
#include <heap.h>
#endif
#include <stdlib.h>
#include "h.h"
#endif

static int iftable[MAXIF+1] = {0};
static int iflevel = 0;
static int mlflag[2] = {0,0};
static char mlmacro[2][128];
static char mlsave[2][LZ];
static char mlwork[2][LZ];
static char * mlptr[2];

extern char ifmessage;

#define NORMAL  0   /* No conditionals in force */
#define OKCOND  1   /* Processing lines, waiting for else or endif */
#define SKIP    2   /* Skipping lines, waiting for else or endif */
#define HADELSE 4   /* Had else, must be waiting for endif */

/*************************************************************************
|                                                                        |
|   >>>>  ifeof                                                          |
|                                                                        |
|   check clean eof                                                      |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
VOID ifeof(void)
#else
VOID ifeof()
#endif

{                     
    if (iflevel == 1) fatal(MSG[42]);         /* EOF expected ifdef */
    if (iflevel > 1) fatal(MSG[43],iflevel);  /* EOF expected ifdefs */
}

/*************************************************************************
|                                                                        |
|   >>>>  ifeoc                                                          |
|                                                                        |
|   check clean end of commands                                          |
|                                                                        |
*************************************************************************/

#if PANEWFD
VOID ifeoc(void)
#else
VOID ifeoc()
#endif

{                     
    if (iflevel == 1) fatal(MSG[44]);         /* End cmds expected %endif */
    if (iflevel > 1) fatal(MSG[45],iflevel);  /* End cmds expected %endifs */
}

/*************************************************************************
|                                                                        |
|   >>>>  ifproc                                                         |
|                                                                        |
|   check each line, return true if to be ignored                        |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
int ifproc(char * s, int n)
#else
int ifproc(s, n)
char * s;
int n;
#endif

{
    register int            i;
    register int            test;

    switch (n) 
    {
        case H_IF:
        case H_IFN:

            if (iflevel >= (MAXIF)) error(MSG[46],ifmessage,ifmessage);
            s += 4;
            while (pspace(*s)) s++;
            i = istrue(s);
            if (n == H_IFN) i = !i;
            iftable[++iflevel] = 2 - i;
            return 1;

        case H_IFE:
        case H_IFNE:

            if (iflevel >= (MAXIF)) error(MSG[47],ifmessage, ifmessage);
            s += 5;
            while (pspace(*s)) s++;
            i = isthere(s);
            if (n == H_IFNE) i = !i;
            iftable[++iflevel] = 2 - i;
            return 1;

        case H_IFERR:

            if (iflevel >= (MAXIF)) error(MSG[47],ifmessage, ifmessage);
            s += 6;
            while (pspace(*s)) s++;
            if ((*s >= '0') && (*s <= '9')) i = (errorlevel >= (unsigned)atoi(s));
            else i = (errorlevel > 0);
            iftable[++iflevel] = 2 - i;
            return 1;

        case H_ELSE:

            i = iftable[iflevel];
            if ((i == NORMAL) || (i & HADELSE)) 
                error(MSG[48],ifmessage,ifmessage); /* else w/o if */ 
            if (i & OKCOND) i = SKIP | HADELSE;
            else i = OKCOND | HADELSE;
            iftable[iflevel] = i;
            return 1;

        case H_ENDIF:

            if (iftable[iflevel])
            {
                iftable[iflevel] = NORMAL;
                iflevel--;
                return 1;
            }
            error(MSG[49],ifmessage,ifmessage);     /* endif w/o if */

        default:

            test = 0;
            for (i = 0; i <= iflevel; i++) test |= (iftable[i] & SKIP);
            return (test);              /* true if skipping */
    }
}

/*************************************************************************
|                                                                        |
|   >>>>  istrue                                                         |
|                                                                        |
|   check whether if statement is true                                   |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static int istrue(char * s)
#else
static int istrue(s)
char * s;
#endif

{
    char *                  p;              /*  General  */
    char *                  q;              /*  General  */
    struct macro *          mp;
    int                     r;

    p = s;

    while (((q = strchr(p, '=')) != (char *)0) &&
        (p != q) && (q[-1] == '\\'))        /*  Find value */
    {
        register char *         a;
        a = q - 1;      /*  Del \ chr; move rest back  */
        p = q;
        while ((*a++ = *q++) != '\0')
            ;
    }
    if (q != (char *)0)
    {
        register char *         a;

        *q++ = '\0';            /*  Separate name and val  */
        while (pspace(*q))
            q++;
        if ((p = strrchr(q, '\n')) != (char *)0)
            *p = '\0';
        p = s;
        if ((a = gettok(&p)) == (char *)0)
            error(MSG[50],ifmessage);   /* bad conditional on if */
        expand(q);
        if ((mp = getmp(a)) != (struct macro *)0)
        {
            if (mp->m_sub) 
            {
                r = strcmp(q,mp->m_sub);
                free(mp->m_sub);
            }
            else 
                r = strcmp(q,mp->m_val);
        }
        else
            r = strcmp(q,"");
        return (r == 0);
    }
    error(MSG[51],ifmessage);   /* no conditional on if */
    /*lint -e527 */
    return 0;                   /* not reached */
    /*lint -restore */
}

/*************************************************************************
|                                                                        |
|   >>>>  isthere                                                        |
|                                                                        |
|   check whether file exists, true if so                                |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
static int isthere(char * p)
#else
static int isthere(p)
char * p;
#endif

{
    struct name *   q;
    char *          s;
    int             i;
    char            buf[256];

    if ((s = strrchr(p, '\n')) != (char *)0)
        *s = '\0';
    expand(p);
    for (i = 0; i < 255; )
    {
        if ((*p == ' ') || (*p == '\0')) break;
        else buf[i++] = *p++;
    }
    buf[i] = '\0';
    modtime(q = newname(buf));
    return (q->n_time > 0);
}

/*************************************************************************
|                                                                        |
|   >>>>  initml                                                         |
|                                                                        |
|   initialise multiple line processing                                  |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
VOID initml(int level, char * s)
#else
VOID initml(level, s)
int level;
char * s;
#endif

{
    char * p, *q, *r;

    if ((p = pstrstr(s,"${")) == (char *)0)
    {
        mlflag[level] = -1;
        return;
    }
    mlflag[level] = 1;    
    q = psa(&mlsave[level][0],"${");
    p += 2;
    while (pspace(*p)) p++;
    r = q;
    while ((*p != '}') && (*p != ':') && (*p != '\0') && (*p != ' ')) 
        *q++ = *p++;
    *q = '\0';
    strcpy(&mlmacro[level][0],r);
    *q++ = '}';
    *q = '\0';
    expand(&mlsave[level][0]);
    p = psa(&mlwork[level][0],&mlsave[level][0]);
    *++p = '\0';                               /* double null */
    mlptr[level] = &mlwork[level][0];
}

/*************************************************************************
|                                                                        |
|   >>>>  makeml                                                         |
|                                                                        |
|   make a multiple line instance                                        |
|                                                                        |
*************************************************************************/

#ifdef PANEWFD
int makeml(int level)
#else
int makeml(level)
int level;
#endif

{
    char * p;

    if (mlflag[level] == -1)
    {
        return mlflag[level]--;
    }    
    else if (mlflag[level] == -2)
    {
        return 0;
    }
    p = gettok(&mlptr[level]);
    if (p == (char *)0)
    {
        setmacro(&mlmacro[level][0],&mlsave[level][0]);
        return 0;
    }
    setmacro(&mlmacro[level][0],p);
    return 1;
}

